๋ ๋น ๋ฅด๊ณ ํจ์จ์ ์ธ ๊ทธ๋ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฑ๋ฅ์ ์ํด Neo4j ์ฟผ๋ฆฌ ์ต์ ํ๋ฅผ ๋ง์คํฐํ์ธ์. Cypher ๋ชจ๋ฒ ์ฌ๋ก, ์ธ๋ฑ์ฑ ์ ๋ต, ํ๋กํ์ผ๋ง ๊ธฐ๋ฒ ๋ฐ ๊ณ ๊ธ ์ต์ ํ ๋ฐฉ๋ฒ์ ๋ฐฐ์ฐ์ธ์.
๊ทธ๋ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค: Neo4j ์ฟผ๋ฆฌ ์ต์ ํ โ ์ข ํฉ ๊ฐ์ด๋
๊ทธ๋ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค, ํนํ Neo4j๋ ์ํธ ์ฐ๊ฒฐ๋ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๊ณ ๋ถ์ํ๋ ๋ฐ ์ ์ ๋ ๋ง์ด ์ฌ์ฉ๋๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ฐ์ดํฐ ์ธํธ๊ฐ ์ปค์ง์ ๋ฐ๋ผ ํจ์จ์ ์ธ ์ฟผ๋ฆฌ ์คํ์ด ์ค์ํด์ง๋๋ค. ์ด ๊ฐ์ด๋๋ Neo4j ์ฟผ๋ฆฌ ์ต์ ํ ๊ธฐ์ ์ ๋ํ ํฌ๊ด์ ์ธ ๊ฐ์๋ฅผ ์ ๊ณตํ์ฌ ๊ณ ์ฑ๋ฅ ๊ทธ๋ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์๋๋ก ์ง์ํฉ๋๋ค.
์ฟผ๋ฆฌ ์ต์ ํ์ ์ค์์ฑ ์ดํดํ๊ธฐ
์ ์ ํ ์ฟผ๋ฆฌ ์ต์ ํ๊ฐ ์์ผ๋ฉด Neo4j ์ฟผ๋ฆฌ๋ ๋๋ ค์ง๊ณ ๋ฆฌ์์ค๋ฅผ ๋ง์ด ์๋ชจํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ๊ณผ ํ์ฅ์ฑ์ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์ต์ ํ๋ Cypher ์ฟผ๋ฆฌ ์คํ์ ๋ํ ์ดํด, ์ธ๋ฑ์ฑ ์ ๋ต ํ์ฉ, ์ฑ๋ฅ ํ๋กํ์ผ๋ง ๋๊ตฌ ์ฌ์ฉ์ ์กฐํฉ์ ํฌํจํฉ๋๋ค. ๋ชฉํ๋ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฅํ๋ฉด์ ์คํ ์๊ฐ๊ณผ ๋ฆฌ์์ค ์๋น๋ฅผ ์ต์ํํ๋ ๊ฒ์ ๋๋ค.
์ฟผ๋ฆฌ ์ต์ ํ๊ฐ ์ค์ํ ์ด์
- ์ฑ๋ฅ ํฅ์: ๋ ๋น ๋ฅธ ์ฟผ๋ฆฌ ์คํ์ ๋ ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์๋ต์ฑ๊ณผ ๋ ๊ธ์ ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ผ๋ก ์ด์ด์ง๋๋ค.
- ๋ฆฌ์์ค ์๋น ๊ฐ์: ์ต์ ํ๋ ์ฟผ๋ฆฌ๋ CPU ์ฌ์ดํด, ๋ฉ๋ชจ๋ฆฌ, ๋์คํฌ I/O๋ฅผ ๋ ์ ๊ฒ ์๋นํ์ฌ ์ธํ๋ผ ๋น์ฉ์ ์ ๊ฐํฉ๋๋ค.
- ํ์ฅ์ฑ ํฅ์: ํจ์จ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ํตํด Neo4j ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ฑ๋ฅ ์ ํ ์์ด ๋ ํฐ ๋ฐ์ดํฐ ์ธํธ์ ๋ ๋์ ์ฟผ๋ฆฌ ๋ถํ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ๋์์ฑ ๊ฐ์ : ์ต์ ํ๋ ์ฟผ๋ฆฌ๋ ์ ๊ธ ์ถฉ๋๊ณผ ๊ฒฝํฉ์ ์ต์ํํ์ฌ ๋์์ฑ๊ณผ ์ฒ๋ฆฌ๋์ ํฅ์์ํต๋๋ค.
Cypher ์ฟผ๋ฆฌ ์ธ์ด ๊ธฐ๋ณธ
Cypher๋ ๊ทธ๋ํ ํจํด๊ณผ ๊ด๊ณ๋ฅผ ํํํ๊ธฐ ์ํด ์ค๊ณ๋ Neo4j์ ์ ์ธ์ ์ฟผ๋ฆฌ ์ธ์ด์ ๋๋ค. Cypher๋ฅผ ์ดํดํ๋ ๊ฒ์ด ํจ๊ณผ์ ์ธ ์ฟผ๋ฆฌ ์ต์ ํ์ ์ฒซ๊ฑธ์์ ๋๋ค.
๊ธฐ๋ณธ Cypher ๊ตฌ๋ฌธ
๋ค์์ ๊ธฐ๋ณธ์ ์ธ Cypher ๊ตฌ๋ฌธ ์์์ ๋ํ ๊ฐ๋ตํ ๊ฐ์์ ๋๋ค:
- ๋
ธ๋: ๊ทธ๋ํ์ ์ํฐํฐ๋ฅผ ๋ํ๋
๋๋ค. ๊ดํธ๋ก ๋ฌถ์ต๋๋ค:
(node). - ๊ด๊ณ: ๋
ธ๋ ๊ฐ์ ์ฐ๊ฒฐ์ ๋ํ๋
๋๋ค. ๋๊ดํธ๋ก ๋ฌถ๊ณ ํ์ดํ๊ณผ ํ์ดํ๋ก ์ฐ๊ฒฐํฉ๋๋ค:
-[relationship]->๋๋<-[relationship]-๋๋-[relationship]-. - ๋ ์ด๋ธ: ๋
ธ๋๋ฅผ ๋ถ๋ฅํฉ๋๋ค. ๋
ธ๋ ๋ณ์ ๋ค์ ์ถ๊ฐ๋ฉ๋๋ค:
(node:Label). - ์์ฑ: ๋
ธ๋ ๋ฐ ๊ด๊ณ์ ๊ด๋ จ๋ ํค-๊ฐ ์์
๋๋ค:
{property: 'value'}. - ํค์๋:
MATCH,WHERE,RETURN,CREATE,DELETE,SET,MERGE๋ฑ๊ณผ ๊ฐ์ ํค์๋์ ๋๋ค.
์ผ๋ฐ์ ์ธ Cypher ์
- MATCH: ๊ทธ๋ํ์์ ํจํด์ ์ฐพ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
MATCH (a:Person)-[:FRIENDS_WITH]->(b:Person) WHERE a.name = 'Alice' RETURN b - WHERE: ์กฐ๊ฑด์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๋ฅผ ํํฐ๋งํฉ๋๋ค.
MATCH (n:Product) WHERE n.price > 100 RETURN n - RETURN: ์ฟผ๋ฆฌ์์ ๋ฐํํ ๋ฐ์ดํฐ๋ฅผ ์ง์ ํฉ๋๋ค.
MATCH (n:City) RETURN n.name, n.population - CREATE: ์๋ก์ด ๋
ธ๋์ ๊ด๊ณ๋ฅผ ์์ฑํฉ๋๋ค.
CREATE (n:Person {name: 'Bob', age: 30}) - DELETE: ๋
ธ๋์ ๊ด๊ณ๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
MATCH (n:OldNode) DELETE n - SET: ๋
ธ๋์ ๊ด๊ณ์ ์์ฑ์ ์
๋ฐ์ดํธํฉ๋๋ค.
MATCH (n:Product {name: 'Laptop'}) SET n.price = 1200 - MERGE: ๊ธฐ์กด ๋
ธ๋๋ ๊ด๊ณ๋ฅผ ์ฐพ๊ฑฐ๋, ์กด์ฌํ์ง ์์ผ๋ฉด ์๋ก ์์ฑํฉ๋๋ค. ๋ฉฑ๋ฑ ์ฐ์ฐ์ ์ ์ฉํฉ๋๋ค.
MERGE (n:Country {name: 'Germany'}) - WITH: ์ฌ๋ฌ
MATCH์ ์ ์ฐ๊ฒฐํ๊ณ ์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ฌํ ์ ์์ต๋๋ค.MATCH (a:Person)-[:FRIENDS_WITH]->(b:Person) WITH a, count(b) AS friendsCount WHERE friendsCount > 5 RETURN a.name, friendsCount - ORDER BY: ๊ฒฐ๊ณผ๋ฅผ ์ ๋ ฌํฉ๋๋ค.
MATCH (n:Movie) RETURN n ORDER BY n.title - LIMIT: ๋ฐํ๋๋ ๊ฒฐ๊ณผ์ ์๋ฅผ ์ ํํฉ๋๋ค.
MATCH (n:User) RETURN n LIMIT 10 - SKIP: ์ง์ ๋ ์์ ๊ฒฐ๊ณผ๋ฅผ ๊ฑด๋๋๋๋ค.
MATCH (n:Product) RETURN n SKIP 5 LIMIT 10 - UNION/UNION ALL: ์ฌ๋ฌ ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๋ฅผ ๊ฒฐํฉํฉ๋๋ค.
MATCH (n:Movie) WHERE n.genre = 'Action' RETURN n.title UNION ALL MATCH (n:Movie) WHERE n.genre = 'Comedy' RETURN n.title - CALL: ์ ์ฅ ํ๋ก์์ ๋๋ ์ฌ์ฉ์ ์ ์ ํจ์๋ฅผ ์คํํฉ๋๋ค.
CALL db.index.fulltext.createNodeIndex("PersonNameIndex", ["Person"], ["name"])
Neo4j ์ฟผ๋ฆฌ ์คํ ๊ณํ
Neo4j๊ฐ ์ฟผ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ์คํํ๋์ง ์ดํดํ๋ ๊ฒ์ ์ต์ ํ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. Neo4j๋ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๊ณ ์ฒ๋ฆฌํ๋ ์ต์ ์ ๋ฐฉ๋ฒ์ ๊ฒฐ์ ํ๊ธฐ ์ํด ์ฟผ๋ฆฌ ์คํ ๊ณํ์ ์ฌ์ฉํฉ๋๋ค. EXPLAIN ๋ฐ PROFILE ๋ช
๋ น์ ์ฌ์ฉํ์ฌ ์คํ ๊ณํ์ ๋ณผ ์ ์์ต๋๋ค.
EXPLAIN vs. PROFILE
- EXPLAIN: ์ฟผ๋ฆฌ๋ฅผ ์ค์ ๋ก ์คํํ์ง ์๊ณ ๋ ผ๋ฆฌ์ ์คํ ๊ณํ์ ๋ณด์ฌ์ค๋๋ค. Neo4j๊ฐ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ธฐ ์ํด ์ทจํ ๋จ๊ณ๋ฅผ ์ดํดํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
- PROFILE: ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ณ ๊ฐ ๋จ๊ณ์ ๋ํ ์ฒ๋ฆฌ๋ ํ ์, ๋ฐ์ดํฐ๋ฒ ์ด์ค ํํธ ์, ์คํ ์๊ฐ ๋ฑ ์คํ ๊ณํ์ ๋ํ ์์ธํ ํต๊ณ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํ๋ ๋ฐ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
์คํ ๊ณํ ํด์ํ๊ธฐ
์คํ ๊ณํ์ ๊ฐ๊ฐ ํน์ ์์ ์ ์ํํ๋ ์ผ๋ จ์ ์ฐ์ฐ์๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ฐ์ฐ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- NodeByLabelScan: ํน์ ๋ ์ด๋ธ์ ๊ฐ์ง ๋ชจ๋ ๋ ธ๋๋ฅผ ์ค์บํฉ๋๋ค.
- IndexSeek: ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ๋ ธ๋๋ฅผ ์ฐพ์ต๋๋ค.
- Expand(All): ๊ด๊ณ๋ฅผ ์ํํ์ฌ ์ฐ๊ฒฐ๋ ๋ ธ๋๋ฅผ ์ฐพ์ต๋๋ค.
- Filter: ๊ฒฐ๊ณผ์ ํํฐ ์กฐ๊ฑด์ ์ ์ฉํฉ๋๋ค.
- Projection: ๊ฒฐ๊ณผ์์ ํน์ ์์ฑ์ ์ ํํฉ๋๋ค.
- Sort: ๊ฒฐ๊ณผ๋ฅผ ์ ๋ ฌํฉ๋๋ค.
- Limit: ๊ฒฐ๊ณผ ์๋ฅผ ์ ํํฉ๋๋ค.
์คํ ๊ณํ์ ๋ถ์ํ๋ฉด ์ ์ฒด ๋ ธ๋ ์ค์บ์ด๋ ๋ถํ์ํ ํํฐ๋ง๊ณผ ๊ฐ์ด ์ต์ ํํ ์ ์๋ ๋นํจ์จ์ ์ธ ์์ ์ ๋ฐ๊ฒฌํ ์ ์์ต๋๋ค.
์์: ์คํ ๊ณํ ๋ถ์
๋ค์ Cypher ์ฟผ๋ฆฌ๋ฅผ ๊ณ ๋ คํด ๋ณด์ธ์:
EXPLAIN MATCH (p:Person {name: 'Alice'})-[:FRIENDS_WITH]->(f:Person) RETURN f.name
EXPLAIN ์ถ๋ ฅ์ NodeByLabelScan ๋ค์์ Expand(All)์ด ํ์๋ ์ ์์ต๋๋ค. ์ด๋ Neo4j๊ฐ FRIENDS_WITH ๊ด๊ณ๋ฅผ ์ํํ๊ธฐ ์ ์ 'Alice'๋ฅผ ์ฐพ๊ธฐ ์ํด ๋ชจ๋ Person ๋
ธ๋๋ฅผ ์ค์บํ๊ณ ์์์ ๋ํ๋
๋๋ค. name ์์ฑ์ ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด ์ด๋ ๋นํจ์จ์ ์
๋๋ค.
PROFILE MATCH (p:Person {name: 'Alice'})-[:FRIENDS_WITH]->(f:Person) RETURN f.name
PROFILE์ ์คํํ๋ฉด ๊ฐ ์์
์ ์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํํธ ์์ ์๊ฐ์ ๋ณด์ฌ์ฃผ๋ ์คํ ํต๊ณ๊ฐ ์ ๊ณต๋์ด ๋ณ๋ชฉ ํ์์ ๋์ฑ ํ์คํ๊ฒ ํ์ธํ ์ ์์ต๋๋ค.
์ธ๋ฑ์ฑ ์ ๋ต
์ธ๋ฑ์ค๋ Neo4j๊ฐ ์์ฑ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ๋ ธ๋์ ๊ด๊ณ๋ฅผ ์ ์ํ๊ฒ ์ฐพ์ ์ ์๊ฒ ํ์ฌ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด Neo4j๋ ์ข ์ข ์ ์ฒด ์ค์บ์ ์์กดํ๊ฒ ๋๋๋ฐ, ์ด๋ ๋๊ท๋ชจ ๋ฐ์ดํฐ ์ธํธ์์๋ ๋๋ฆฝ๋๋ค.
Neo4j์ ์ธ๋ฑ์ค ์ ํ
- B-ํธ๋ฆฌ ์ธ๋ฑ์ค: ํ์ค ์ธ๋ฑ์ค ์ ํ์ผ๋ก, ๋๋ฑ์ฑ ๋ฐ ๋ฒ์ ์ฟผ๋ฆฌ์ ์ ํฉํฉ๋๋ค. ๊ณ ์ ์ ์ฝ ์กฐ๊ฑด์ ๋ํด ์๋์ผ๋ก ์์ฑ๋๊ฑฐ๋
CREATE INDEX๋ช ๋ น์ ์ฌ์ฉํ์ฌ ์๋์ผ๋ก ์์ฑ๋ฉ๋๋ค. - ์ ์ฒด ํ
์คํธ(Fulltext) ์ธ๋ฑ์ค: ํค์๋์ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ํ
์คํธ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๋๋ก ์ค๊ณ๋์์ต๋๋ค.
db.index.fulltext.createNodeIndex๋๋db.index.fulltext.createRelationshipIndexํ๋ก์์ ๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ๋ฉ๋๋ค. - ํฌ์ธํธ(Point) ์ธ๋ฑ์ค: ๊ณต๊ฐ ๋ฐ์ดํฐ์ ์ต์ ํ๋์ด ์ง๋ฆฌ์ ์ขํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ํจ์จ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
db.index.point.createNodeIndex๋๋db.index.point.createRelationshipIndexํ๋ก์์ ๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ๋ฉ๋๋ค. - ๋ฒ์(Range) ์ธ๋ฑ์ค: ๋ฒ์ ์ฟผ๋ฆฌ์ ํน๋ณํ ์ต์ ํ๋์ด ์์ผ๋ฉฐ, ํน์ ์ํฌ๋ก๋์ ๋ํด B-ํธ๋ฆฌ ์ธ๋ฑ์ค๋ณด๋ค ํฅ์๋ ์ฑ๋ฅ์ ์ ๊ณตํฉ๋๋ค. Neo4j 5.7 ์ด์์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ธ๋ฑ์ค ์์ฑ ๋ฐ ๊ด๋ฆฌ
Cypher ๋ช ๋ น์ ์ฌ์ฉํ์ฌ ์ธ๋ฑ์ค๋ฅผ ์์ฑํ ์ ์์ต๋๋ค:
B-ํธ๋ฆฌ ์ธ๋ฑ์ค:
CREATE INDEX PersonName FOR (n:Person) ON (n.name)
๋ณตํฉ ์ธ๋ฑ์ค:
CREATE INDEX PersonNameAge FOR (n:Person) ON (n.name, n.age)
์ ์ฒด ํ ์คํธ ์ธ๋ฑ์ค:
CALL db.index.fulltext.createNodeIndex("PersonNameIndex", ["Person"], ["name"])
ํฌ์ธํธ ์ธ๋ฑ์ค:
CALL db.index.point.createNodeIndex("LocationIndex", ["Venue"], ["latitude", "longitude"], {spatial.wgs-84: true})
SHOW INDEXES ๋ช
๋ น์ ์ฌ์ฉํ์ฌ ๊ธฐ์กด ์ธ๋ฑ์ค๋ฅผ ๋์ดํ ์ ์์ต๋๋ค:
SHOW INDEXES
๊ทธ๋ฆฌ๊ณ DROP INDEX ๋ช
๋ น์ ์ฌ์ฉํ์ฌ ์ธ๋ฑ์ค๋ฅผ ์ญ์ ํ ์ ์์ต๋๋ค:
DROP INDEX PersonName
์ธ๋ฑ์ฑ ๋ชจ๋ฒ ์ฌ๋ก
- ์์ฃผ ์ฟผ๋ฆฌ๋๋ ์์ฑ์ ์ธ๋ฑ์ค ์์ฑ:
WHERE์ ๊ณผMATCHํจํด์์ ์ฌ์ฉ๋๋ ์์ฑ์ ์๋ณํฉ๋๋ค. - ์ฌ๋ฌ ์์ฑ์ ๋ํด ๋ณตํฉ ์ธ๋ฑ์ค ์ฌ์ฉ: ์ฌ๋ฌ ์์ฑ์ ํจ๊ป ์์ฃผ ์ฟผ๋ฆฌํ๋ ๊ฒฝ์ฐ ๋ณตํฉ ์ธ๋ฑ์ค๋ฅผ ์์ฑํฉ๋๋ค.
- ๊ณผ๋ํ ์ธ๋ฑ์ฑ ํผํ๊ธฐ: ๋๋ฌด ๋ง์ ์ธ๋ฑ์ค๋ ์ฐ๊ธฐ ์์ ์ ๋๋ฆฌ๊ฒ ํ ์ ์์ต๋๋ค. ์ฟผ๋ฆฌ์์ ์ค์ ๋ก ์ฌ์ฉ๋๋ ์์ฑ์๋ง ์ธ๋ฑ์ค๋ฅผ ์์ฑํฉ๋๋ค.
- ์์ฑ์ ์นด๋๋๋ฆฌํฐ ๊ณ ๋ ค: ์ธ๋ฑ์ค๋ ์นด๋๋๋ฆฌํฐ๊ฐ ๋์(์ฆ, ๊ณ ์ ํ ๊ฐ์ด ๋ง์) ์์ฑ์ ๋ ํจ๊ณผ์ ์ ๋๋ค.
- ์ธ๋ฑ์ค ์ฌ์ฉ ๋ชจ๋ํฐ๋ง:
PROFILE๋ช ๋ น์ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ์์ ์ธ๋ฑ์ค๊ฐ ์ฌ์ฉ๋๊ณ ์๋์ง ํ์ธํฉ๋๋ค. - ์ฃผ๊ธฐ์ ์ผ๋ก ์ธ๋ฑ์ค ์ฌ๊ตฌ์ฑ: ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ธ๋ฑ์ค๊ฐ ์กฐ๊ฐํ๋ ์ ์์ต๋๋ค. ์ด๋ฅผ ์ฌ๊ตฌ์ฑํ๋ฉด ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์์: ์ฑ๋ฅ์ ์ํ ์ธ๋ฑ์ฑ
Person ๋
ธ๋์ FRIENDS_WITH ๊ด๊ณ๊ฐ ์๋ ์์
๋คํธ์ํฌ ๊ทธ๋ํ๋ฅผ ์๊ฐํด ๋ณด์ธ์. ํน์ ์ฌ๋์ ์ด๋ฆ์ ๊ธฐ์ค์ผ๋ก ์น๊ตฌ๋ฅผ ์์ฃผ ์ฟผ๋ฆฌํ๋ ๊ฒฝ์ฐ, Person ๋
ธ๋์ name ์์ฑ์ ์ธ๋ฑ์ค๋ฅผ ์์ฑํ๋ฉด ์ฑ๋ฅ์ด ํฌ๊ฒ ํฅ์๋ ์ ์์ต๋๋ค.
CREATE INDEX PersonName FOR (n:Person) ON (n.name)
์ธ๋ฑ์ค๋ฅผ ์์ฑํ ํ ๋ค์ ์ฟผ๋ฆฌ๋ ํจ์ฌ ๋น ๋ฅด๊ฒ ์คํ๋ฉ๋๋ค:
MATCH (p:Person {name: 'Alice'})-[:FRIENDS_WITH]->(f:Person) RETURN f.name
์ธ๋ฑ์ค ์์ฑ ์ ํ์ PROFILE์ ์ฌ์ฉํ๋ฉด ์ฑ๋ฅ ํฅ์์ ํ์ธํ ์ ์์ต๋๋ค.
Cypher ์ฟผ๋ฆฌ ์ต์ ํ ๊ธฐ๋ฒ
์ธ๋ฑ์ฑ ์ธ์๋ ์ฌ๋ฌ Cypher ์ฟผ๋ฆฌ ์ต์ ํ ๊ธฐ๋ฒ์ด ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
1. ์ฌ๋ฐ๋ฅธ MATCH ํจํด ์ฌ์ฉ
MATCH ํจํด์ ์์ ์์๋ ์ฑ๋ฅ์ ํฐ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์ฒ๋ฆฌํด์ผ ํ ๋
ธ๋์ ๊ด๊ณ์ ์๋ฅผ ์ค์ด๊ธฐ ์ํด ๊ฐ์ฅ ์ ํ์ ์ธ ๊ธฐ์ค์ผ๋ก ์์ํ์ธ์.
๋นํจ์จ์ :
MATCH (a)-[:RELATED_TO]->(b:Product) WHERE b.category = 'Electronics' AND a.city = 'London' RETURN a, b
์ต์ ํ:
MATCH (b:Product {category: 'Electronics'})<-[:RELATED_TO]-(a {city: 'London'}) RETURN a, b
์ต์ ํ๋ ๋ฒ์ ์์๋ category ์์ฑ์ ๊ฐ์ง Product ๋
ธ๋์์ ์์ํ๋๋ฐ, ์ด๋ ๋ชจ๋ ๋
ธ๋๋ฅผ ์ค์บํ ๋ค์ ๋์๋ก ํํฐ๋งํ๋ ๊ฒ๋ณด๋ค ๋ ์ ํ์ ์ผ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค.
2. ๋ฐ์ดํฐ ์ ์ก ์ต์ํ
๋ถํ์ํ ๋ฐ์ดํฐ ๋ฐํ์ ํผํ์ธ์. RETURN ์ ์์ ํ์ํ ์์ฑ๋ง ์ ํํ์ธ์.
๋นํจ์จ์ :
MATCH (n:User {country: 'USA'}) RETURN n
์ต์ ํ:
MATCH (n:User {country: 'USA'}) RETURN n.name, n.email
name๊ณผ email ์์ฑ๋ง ๋ฐํํ๋ฉด ์ ์ก๋๋ ๋ฐ์ดํฐ ์์ด ์ค์ด๋ค์ด ์ฑ๋ฅ์ด ํฅ์๋ฉ๋๋ค.
3. ์ค๊ฐ ๊ฒฐ๊ณผ์ WITH ์ฌ์ฉ
WITH ์ ์ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ MATCH ์ ์ ์ฐ๊ฒฐํ๊ณ ์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ฌํ ์ ์์ต๋๋ค. ์ด๋ ๋ณต์กํ ์ฟผ๋ฆฌ๋ฅผ ๋ ์๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ๋จ๊ณ๋ก ๋๋๋ ๋ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
์์: ํจ๊ป ์์ฃผ ๊ตฌ๋งค๋๋ ๋ชจ๋ ์ ํ ์ฐพ๊ธฐ.
MATCH (o:Order)-[:CONTAINS]->(p:Product)
WITH o, collect(p) AS products
WHERE size(products) > 1
UNWIND products AS product1
UNWIND products AS product2
WHERE id(product1) < id(product2)
WITH product1, product2, count(*) AS co_purchases
ORDER BY co_purchases DESC
LIMIT 10
RETURN product1.name, product2.name, co_purchases
WITH ์ ์ ์ฌ์ฉํ๋ฉด ๊ฐ ์ฃผ๋ฌธ์ ์ ํ์ ์์งํ๊ณ , ๋ ๊ฐ ์ด์์ ์ ํ์ด ์๋ ์ฃผ๋ฌธ์ ํํฐ๋งํ ๋ค์, ๋ค๋ฅธ ์ ํ ๊ฐ์ ๋์ ๊ตฌ๋งค๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
4. ๋งค๊ฐ๋ณ์ํ๋ ์ฟผ๋ฆฌ ํ์ฉ
๋งค๊ฐ๋ณ์ํ๋ ์ฟผ๋ฆฌ๋ Cypher ์ฃผ์ ๊ณต๊ฒฉ์ ๋ฐฉ์งํ๊ณ Neo4j๊ฐ ์ฟผ๋ฆฌ ์คํ ๊ณํ์ ์ฌ์ฌ์ฉํ ์ ์๊ฒ ํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค. ์ฟผ๋ฆฌ ๋ฌธ์์ด์ ๊ฐ์ ์ง์ ํฌํจํ๋ ๋์ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ธ์.
์์ (Neo4j ๋๋ผ์ด๋ฒ ์ฌ์ฉ):
session.run("MATCH (n:Person {name: $name}) RETURN n", {name: 'Alice'})
์ฌ๊ธฐ์ $name์ ์ฟผ๋ฆฌ์ ์ ๋ฌ๋๋ ๋งค๊ฐ๋ณ์์
๋๋ค. ์ด๋ฅผ ํตํด Neo4j๋ ์ฟผ๋ฆฌ ์คํ ๊ณํ์ ์บ์ํ๊ณ ๋ค๋ฅธ name ๊ฐ์ ๋ํด ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
5. ์นดํฐ์ ํ๋ก๋ํธ(Cartesian Product) ํผํ๊ธฐ
์นดํฐ์ ํ๋ก๋ํธ๋ ์ฟผ๋ฆฌ์ ์ฌ๋ฌ ๋
๋ฆฝ์ ์ธ MATCH ์ ์ด ์์ ๋ ๋ฐ์ํฉ๋๋ค. ์ด๋ก ์ธํด ๋ถํ์ํ ์กฐํฉ์ด ๋๋์ผ๋ก ์์ฑ๋์ด ์ฟผ๋ฆฌ ์คํ์ด ํฌ๊ฒ ๋๋ ค์ง ์ ์์ต๋๋ค. MATCH ์ ์ด ์๋ก ๊ด๋ จ๋๋๋ก ํ์ธ์.
๋นํจ์จ์ :
MATCH (a:Person {city: 'London'})
MATCH (b:Product {category: 'Electronics'})
RETURN a, b
์ต์ ํ (Person๊ณผ Product ์ฌ์ด์ ๊ด๊ณ๊ฐ ์๋ ๊ฒฝ์ฐ):
MATCH (a:Person {city: 'London'})-[:PURCHASED]->(b:Product {category: 'Electronics'})
RETURN a, b
์ต์ ํ๋ ๋ฒ์ ์์๋ Person๊ณผ Product ๋
ธ๋๋ฅผ ์ฐ๊ฒฐํ๊ธฐ ์ํด ๊ด๊ณ(PURCHASED)๋ฅผ ์ฌ์ฉํ์ฌ ์นดํฐ์ ํ๋ก๋ํธ๋ฅผ ํผํฉ๋๋ค.
6. APOC ํ๋ก์์ ๋ฐ ํจ์ ์ฌ์ฉ
APOC(Awesome Procedures On Cypher) ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ Cypher์ ๊ธฐ๋ฅ์ ํฅ์์ํค๊ณ ์ฑ๋ฅ์ ๊ฐ์ ํ ์ ์๋ ์ ์ฉํ ํ๋ก์์ ์ ํจ์์ ๋ชจ์์ ๋๋ค. APOC์๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ/๋ด๋ณด๋ด๊ธฐ, ๊ทธ๋ํ ๋ฆฌํฉํ ๋ง ๋ฑ์ ์ํ ๊ธฐ๋ฅ์ด ํฌํจ๋์ด ์์ต๋๋ค.
์์: ๋ฐฐ์น ์ฒ๋ฆฌ๋ฅผ ์ํ apoc.periodic.iterate ์ฌ์ฉ
CALL apoc.periodic.iterate(
"MATCH (n:OldNode) RETURN n",
"CREATE (newNode:NewNode) SET newNode = n.properties WITH n DELETE n",
{batchSize: 1000, parallel: true}
)
์ด ์๋ OldNode์์ NewNode๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์น๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ๊ธฐ ์ํด apoc.periodic.iterate๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ์ด๋ ๋จ์ผ ํธ๋์ญ์
์์ ๋ชจ๋ ๋
ธ๋๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ํจ์จ์ ์
๋๋ค.
7. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ฑ ๊ณ ๋ ค
Neo4j์ ๊ตฌ์ฑ๋ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์ฃผ์ ๊ตฌ์ฑ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํ ํฌ๊ธฐ: Neo4j์ ์ถฉ๋ถํ ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํฉ๋๋ค.
dbms.memory.heap.max_size์ค์ ์ ์ฌ์ฉํฉ๋๋ค. - ํ์ด์ง ์บ์: ํ์ด์ง ์บ์๋ ์์ฃผ ์ก์ธ์คํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํฉ๋๋ค. ๋ ๋์ ์ฑ๋ฅ์ ์ํด ํ์ด์ง ์บ์ ํฌ๊ธฐ(
dbms.memory.pagecache.size)๋ฅผ ๋๋ฆฝ๋๋ค. - ํธ๋์ญ์ ๋ก๊น : ์ฑ๋ฅ๊ณผ ๋ฐ์ดํฐ ๋ด๊ตฌ์ฑ์ ๊ท ํ์ ๋ง์ถ๊ธฐ ์ํด ํธ๋์ญ์ ๋ก๊น ์ค์ ์ ์กฐ์ ํฉ๋๋ค.
๊ณ ๊ธ ์ต์ ํ ๊ธฐ๋ฒ
๋ณต์กํ ๊ทธ๋ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ๋ ๊ณ ๊ธ ์ต์ ํ ๊ธฐ์ ์ด ํ์ํ ์ ์์ต๋๋ค.
1. ๊ทธ๋ํ ๋ฐ์ดํฐ ๋ชจ๋ธ๋ง
๊ทธ๋ํ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ธ๋งํ๋ ๋ฐฉ์์ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ํฐ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ๋ค์ ์์น์ ๊ณ ๋ คํ์ธ์:
- ์ฌ๋ฐ๋ฅธ ๋ ธ๋ ๋ฐ ๊ด๊ณ ์ ํ ์ ํ: ๋ฐ์ดํฐ ๋๋ฉ์ธ์ ๊ด๊ณ์ ์ํฐํฐ๋ฅผ ๋ฐ์ํ๋๋ก ๊ทธ๋ํ ์คํค๋ง๋ฅผ ์ค๊ณํฉ๋๋ค.
- ๋ ์ด๋ธ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉ: ๋ ธ๋์ ๊ด๊ณ๋ฅผ ๋ถ๋ฅํ๋ ๋ฐ ๋ ์ด๋ธ์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ฅผ ํตํด Neo4j๋ ์ ํ์ ๋ฐ๋ผ ๋ ธ๋๋ฅผ ์ ์ํ๊ฒ ํํฐ๋งํ ์ ์์ต๋๋ค.
- ๊ณผ๋ํ ์์ฑ ์ฌ์ฉ ํผํ๊ธฐ: ์์ฑ์ ์ ์ฉํ์ง๋ง ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ์ฟผ๋ฆฌ ์ฑ๋ฅ์ด ์ ํ๋ ์ ์์ต๋๋ค. ์์ฃผ ์ฟผ๋ฆฌ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ํ๋ด๊ธฐ ์ํด ๊ด๊ณ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.
- ๋ฐ์ดํฐ ๋น์ ๊ทํ: ๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ๋น์ ๊ทํํ๋ฉด ์กฐ์ธ์ ํ์์ฑ์ ์ค์ฌ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ฐ์ดํฐ ์ค๋ณต์ฑ๊ณผ ์ผ๊ด์ฑ์ ์ ์ํด์ผ ํฉ๋๋ค.
2. ์ ์ฅ ํ๋ก์์ ๋ฐ ์ฌ์ฉ์ ์ ์ ํจ์ ์ฌ์ฉ
์ ์ฅ ํ๋ก์์ ๋ฐ ์ฌ์ฉ์ ์ ์ ํจ์(UDF)๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณต์กํ ๋ก์ง์ ์บก์ํํ๊ณ Neo4j ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ด์์ ์ง์ ์คํํ ์ ์์ต๋๋ค. ์ด๋ ๋คํธ์ํฌ ์ค๋ฒํค๋๋ฅผ ์ค์ด๊ณ Neo4j๊ฐ ์ฝ๋ ์คํ์ ์ต์ ํํ๋๋ก ํ์ฉํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์์ (Java๋ก UDF ์์ฑ):
@Procedure(name = "custom.distance", mode = Mode.READ)
@Description("Calculates the distance between two points on Earth.")
public Double distance(@Name("lat1") Double lat1, @Name("lon1") Double lon1,
@Name("lat2") Double lat2, @Name("lon2") Double lon2) {
// Implementation of the distance calculation
return calculateDistance(lat1, lon1, lat2, lon2);
}
๊ทธ๋ฐ ๋ค์ Cypher์์ UDF๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค:
RETURN custom.distance(34.0522, -118.2437, 40.7128, -74.0060) AS distance
3. ๊ทธ๋ํ ์๊ณ ๋ฆฌ์ฆ ํ์ฉ
Neo4j๋ PageRank, ์ต๋จ ๊ฒฝ๋ก, ์ปค๋ฎค๋ํฐ ๊ฐ์ง ๋ฑ ๋ค์ํ ๊ทธ๋ํ ์๊ณ ๋ฆฌ์ฆ์ ๋ํ ๋ด์ฅ ์ง์์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ ๊ด๊ณ๋ฅผ ๋ถ์ํ๊ณ ๊ทธ๋ํ ๋ฐ์ดํฐ์์ ํต์ฐฐ๋ ฅ์ ์ถ์ถํ ์ ์์ต๋๋ค.
์์: PageRank ๊ณ์ฐ
CALL algo.pageRank.stream('Person', 'FRIENDS_WITH', {iterations:20, dampingFactor:0.85})
YIELD nodeId, score
RETURN nodeId, score
ORDER BY score DESC
LIMIT 10
4. ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง ๋ฐ ํ๋
Neo4j ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฑ๋ฅ์ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๊ณ ๊ฐ์ ํ ์์ญ์ ์๋ณํฉ๋๋ค. ๋ค์ ๋๊ตฌ์ ๊ธฐ์ ์ ์ฌ์ฉํ์ธ์:
- Neo4j ๋ธ๋ผ์ฐ์ : ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ณ ์ฑ๋ฅ์ ๋ถ์ํ๊ธฐ ์ํ ๊ทธ๋ํฝ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Neo4j Bloom: ๊ทธ๋ํ ๋ฐ์ดํฐ๋ฅผ ์๊ฐํํ๊ณ ์ํธ ์์ฉํ ์ ์๋ ๊ทธ๋ํ ํ์ ๋๊ตฌ์ ๋๋ค.
- Neo4j ๋ชจ๋ํฐ๋ง: ์ฟผ๋ฆฌ ์คํ ์๊ฐ, CPU ์ฌ์ฉ๋, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋, ๋์คํฌ I/O์ ๊ฐ์ ์ฃผ์ ๋ฉํธ๋ฆญ์ ๋ชจ๋ํฐ๋งํฉ๋๋ค.
- Neo4j ๋ก๊ทธ: ์ค๋ฅ ๋ฐ ๊ฒฝ๊ณ ์ ๋ํด Neo4j ๋ก๊ทธ๋ฅผ ๋ถ์ํฉ๋๋ค.
- ์ ๊ธฐ์ ์ผ๋ก ์ฟผ๋ฆฌ ๊ฒํ ๋ฐ ์ต์ ํ: ๋๋ฆฐ ์ฟผ๋ฆฌ๋ฅผ ์๋ณํ๊ณ ์ด ๊ฐ์ด๋์ ์ค๋ช ๋ ์ต์ ํ ๊ธฐ์ ์ ์ ์ฉํฉ๋๋ค.
์ค์ ์ฌ๋ก
Neo4j ์ฟผ๋ฆฌ ์ต์ ํ์ ๋ช ๊ฐ์ง ์ค์ ์ฌ๋ก๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
1. ์ ์ ์๊ฑฐ๋ ์ถ์ฒ ์์ง
ํ ์ ์ ์๊ฑฐ๋ ํ๋ซํผ์ Neo4j๋ฅผ ์ฌ์ฉํ์ฌ ์ถ์ฒ ์์ง์ ๊ตฌ์ถํฉ๋๋ค. ๊ทธ๋ํ๋ User ๋
ธ๋, Product ๋
ธ๋ ๋ฐ PURCHASED ๊ด๊ณ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ํ๋ซํผ์ ํจ๊ป ์์ฃผ ๊ตฌ๋งค๋๋ ์ ํ์ ์ถ์ฒํ๊ณ ์ถ์ดํฉ๋๋ค.
์ด๊ธฐ ์ฟผ๋ฆฌ (๋๋ฆผ):
MATCH (u:User)-[:PURCHASED]->(p1:Product), (u)-[:PURCHASED]->(p2:Product)
WHERE p1 <> p2
RETURN p1.name, p2.name, count(*) AS co_purchases
ORDER BY co_purchases DESC
LIMIT 10
์ต์ ํ๋ ์ฟผ๋ฆฌ (๋น ๋ฆ):
MATCH (o:Order)-[:CONTAINS]->(p:Product)
WITH o, collect(p) AS products
WHERE size(products) > 1
UNWIND products AS product1
UNWIND products AS product2
WHERE id(product1) < id(product2)
WITH product1, product2, count(*) AS co_purchases
ORDER BY co_purchases DESC
LIMIT 10
RETURN product1.name, product2.name, co_purchases
์ต์ ํ๋ ์ฟผ๋ฆฌ์์๋ WITH ์ ์ ์ฌ์ฉํ์ฌ ๊ฐ ์ฃผ๋ฌธ์ ์ ํ์ ์์งํ ๋ค์ ๋ค๋ฅธ ์ ํ ๊ฐ์ ๋์ ๊ตฌ๋งค๋ฅผ ์ฐพ์ต๋๋ค. ์ด๋ ๋ชจ๋ ๊ตฌ๋งค๋ ์ ํ ๊ฐ์ ์นดํฐ์ ํ๋ก๋ํธ๋ฅผ ์์ฑํ๋ ์ด๊ธฐ ์ฟผ๋ฆฌ๋ณด๋ค ํจ์ฌ ํจ์จ์ ์
๋๋ค.
2. ์์ ๋คํธ์ํฌ ๋ถ์
ํ ์์
๋คํธ์ํฌ๋ Neo4j๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ๊ฐ์ ์ฐ๊ฒฐ์ ๋ถ์ํฉ๋๋ค. ๊ทธ๋ํ๋ Person ๋
ธ๋์ FRIENDS_WITH ๊ด๊ณ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ํ๋ซํผ์ ๋คํธ์ํฌ์์ ์ํฅ๋ ฅ ์๋ ์ฌ๋์ ์ฐพ๊ณ ์ถ์ดํฉ๋๋ค.
์ด๊ธฐ ์ฟผ๋ฆฌ (๋๋ฆผ):
MATCH (p:Person)-[:FRIENDS_WITH]->(f:Person)
RETURN p.name, count(f) AS friends_count
ORDER BY friends_count DESC
LIMIT 10
์ต์ ํ๋ ์ฟผ๋ฆฌ (๋น ๋ฆ):
MATCH (p:Person)
RETURN p.name, size((p)-[:FRIENDS_WITH]->()) AS friends_count
ORDER BY friends_count DESC
LIMIT 10
์ต์ ํ๋ ์ฟผ๋ฆฌ์์๋ size() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์น๊ตฌ ์๋ฅผ ์ง์ ๊ณ์ฐํฉ๋๋ค. ์ด๋ ๋ชจ๋ FRIENDS_WITH ๊ด๊ณ๋ฅผ ์ํํด์ผ ํ๋ ์ด๊ธฐ ์ฟผ๋ฆฌ๋ณด๋ค ๋ ํจ์จ์ ์
๋๋ค.
๋ํ, Person ๋ ์ด๋ธ์ ์ธ๋ฑ์ค๋ฅผ ์์ฑํ๋ฉด ์ด๊ธฐ ๋
ธ๋ ์กฐํ๊ฐ ๋นจ๋ผ์ง๋๋ค:
CREATE INDEX PersonLabel FOR (p:Person) ON (p)
3. ์ง์ ๊ทธ๋ํ ๊ฒ์
ํ ์ง์ ๊ทธ๋ํ๋ Neo4j๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ ์ํฐํฐ์ ๊ทธ ๊ด๊ณ์ ๋ํ ์ ๋ณด๋ฅผ ์ ์ฅํฉ๋๋ค. ํ๋ซํผ์ ๊ด๋ จ ์ํฐํฐ๋ฅผ ์ฐพ๊ธฐ ์ํ ๊ฒ์ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๊ณ ์ถ์ดํฉ๋๋ค.
์ด๊ธฐ ์ฟผ๋ฆฌ (๋๋ฆผ):
MATCH (e1)-[:RELATED_TO*]->(e2)
WHERE e1.name = 'Neo4j'
RETURN e2.name
์ต์ ํ๋ ์ฟผ๋ฆฌ (๋น ๋ฆ):
MATCH (e1 {name: 'Neo4j'})-[:RELATED_TO*1..3]->(e2)
RETURN e2.name
์ต์ ํ๋ ์ฟผ๋ฆฌ์์๋ ๊ด๊ณ ์ํ ๊น์ด(*1..3)๋ฅผ ์ง์ ํ์ฌ ์ํํด์ผ ํ ๊ด๊ณ์ ์๋ฅผ ์ ํํฉ๋๋ค. ์ด๋ ๊ฐ๋ฅํ ๋ชจ๋ ๊ด๊ณ๋ฅผ ์ํํ๋ ์ด๊ธฐ ์ฟผ๋ฆฌ๋ณด๋ค ๋ ํจ์จ์ ์
๋๋ค.
๋ํ `name` ์์ฑ์ ์ ์ฒด ํ ์คํธ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๊ธฐ ๋ ธ๋ ์กฐํ๋ฅผ ๊ฐ์ํํ ์ ์์ต๋๋ค:
CALL db.index.fulltext.createNodeIndex("EntityNameIndex", ["Entity"], ["name"])
๊ฒฐ๋ก
Neo4j ์ฟผ๋ฆฌ ์ต์ ํ๋ ๊ณ ์ฑ๋ฅ ๊ทธ๋ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์์ ์ ๋๋ค. Cypher ์ฟผ๋ฆฌ ์คํ์ ์ดํดํ๊ณ , ์ธ๋ฑ์ฑ ์ ๋ต์ ํ์ฉํ๊ณ , ์ฑ๋ฅ ํ๋กํ์ผ๋ง ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๊ณ , ๋ค์ํ ์ต์ ํ ๊ธฐ์ ์ ์ ์ฉํจ์ผ๋ก์จ ์ฟผ๋ฆฌ์ ์๋์ ํจ์จ์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฑ๋ฅ์ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๊ณ ๋ฐ์ดํฐ ๋ฐ ์ฟผ๋ฆฌ ์ํฌ๋ก๋๊ฐ ๋ฐ์ ํจ์ ๋ฐ๋ผ ์ต์ ํ ์ ๋ต์ ์กฐ์ ํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ์ด ๊ฐ์ด๋๋ Neo4j ์ฟผ๋ฆฌ ์ต์ ํ๋ฅผ ๋ง์คํฐํ๊ณ ํ์ฅ ๊ฐ๋ฅํ๋ฉฐ ์ฑ๋ฅ์ด ๋ฐ์ด๋ ๊ทธ๋ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ฒฌ๊ณ ํ ๊ธฐ๋ฐ์ ์ ๊ณตํฉ๋๋ค.
์ด๋ฌํ ๊ธฐ์ ์ ๊ตฌํํจ์ผ๋ก์จ Neo4j ๊ทธ๋ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ต์ ์ ์ฑ๋ฅ์ ์ ๊ณตํ๊ณ ์กฐ์ง์ ๊ท์คํ ๋ฆฌ์์ค๊ฐ ๋๋๋ก ๋ณด์ฅํ ์ ์์ต๋๋ค.